/**
 * @author https://xhcss.com/Browser/article/141
 */
import CryptoJS from "crypto-js";
import WebSocket from "ws";
const APPID = process.env.XH_APPID;
const API_SECRET = process.env.XH_API_SECRET;
const API_KEY = process.env.XH_API_KEY;


/**
 * 获取携带token的  webscoket url
 * @param href 如果携带了连接，则以此为准
 * @returns url
 */
export const getWebsocketUrl = (
  apiKey?: string,
  apiSecret?: string
): string => {
  apiKey = apiKey ?? API_KEY;
  apiSecret = apiSecret ?? API_SECRET;
  var url = `wss://spark-api.xf-yun.com/v1.1/chat`;
  var host = "https://websocket.xhcss.com";
  var date = (new Date() as any).toGMTString();
  var algorithm = "hmac-sha256";
  var headers = "host date request-line";
  let version: string = "";
  version = "/v1.1/chat";
  var signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${version} HTTP/1.1`;
  var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
  var signature = CryptoJS.enc.Base64.stringify(signatureSha);
  var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
  var authorization = btoa(authorizationOrigin);
  url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;

  return url;
};

/**
 * websockets 封装类
 */
class SocketsXinghuo {
  url?: string; // 连接地址
  socket?: any; // socket实类
  isOnline: boolean; // 是否连接 , 这里是考虑到每次只能发送一条，一条结束前，为true则不能让人继续发消息
  APPID: string;
  data: string[]; // 一条消息星火模型会多次webscoket 返回，所以进行拼接
  resolve?: any; // 成功后的回调
  reject?:any
  callback?: Function;
  constructor(option?: ChatOption) {
    this.socket = undefined;
    this.isOnline = false;
    this.url = getWebsocketUrl(option?.API_KEY, option?.API_SECRET);
    this.APPID = option?.APPID ?? APPID;
    this.APPID = option?.APPID ?? APPID;
    this.callback = option.callback;
    // 合并的消息
    this.data = [];
    this.resolve = undefined;
    this.reject=undefined
  }

  /**
   * 连接url
   * @returns WebSocket
   */
  connectSocket() {
    return new Promise((resolve, reject) => {
      if (this.socket && this.isOnline) {
        resolve(this.socket);
      } else {
        const url = this.url!;
        this.socket = new WebSocket(url);
        // 监听连接成功
        // 监听连接成功
        this.socket.onopen = () => {
          console.log("链接成功");
          this.isOnline = true;
          resolve(this.socket);
        };
        // 监听接收信息
        this.socket.onmessage = (e: any) => this.onMessage(e);
        // 监听断开
        this.socket.onclose = (e: any) => this.onclose(e);
        // 监听错误
        this.socket.onerror = (err: any) => {
           this.reject()
          console.log("链接错误1"); 
          //   console.log(err)
          this.isOnline = false;
        };
      }
    });
  }
  onclose(err: any) {
    console.log("链接关闭");
    //  console.log(err)
  }
  /**
   * 收到消息
   * @param data ChatFace
   */
  onMessage(data: MessageData) {
    console.log("收到消息1");

    const obj: ChatFace = JSON.parse(data.data);
    const arrText = obj.payload.choices.text;
    arrText.forEach((item) => {
      this.data.push(item.content);
      this.callback && this.callback(item.content);
    });
    if (obj.header.status === 2) {
      this.resolve && this.resolve(this.data.join("\r\n"));
      this.close();
    }
  }
  /**
   * 主动关闭，暂时无用
   */
  close() {
    this.socket?.close();
    this.socket = undefined;
    this.isOnline = false;
    this.data = [];
    this.resolve = undefined;
  }
  getParams(str: string) {
    return {
      header: {
        app_id: this.APPID,
      },
      parameter: {
        chat: {
          domain: "general",
          temperature: 0.5,
          max_tokens: 1024,
        },
      },
      payload: {
        message: {
          text: [{ role: "user", content: str }],
        },
      },
    };
  }
  /**
   * 发送消息
   * @param str  发送的消息文字
   * @returns
   */
  send(str: string): Promise<string> {
    return new Promise((resolve, reject) => {
      this.connectSocket().then((res) => {
        const params = this.getParams(str);
        this.resolve = resolve;
        this.socket?.send(JSON.stringify(params));
      });
    });
  }
}
export default SocketsXinghuo;

interface MessageData {
  data: string;
}
/**
 * 组件传入的字段
 */
interface ChatOption {
  uid?: string; // 传入的用户id
  url?: string; // 连接
  APPID?: string; // 传入的appid，便于让用户用自己的使用
  API_SECRET?: string;
  API_KEY?: string;
  callback?: Function; // 如果传入回调,则每次收到消息都会传回回调
}

interface ChatFace {
  header: {
    /**
     * 错误码，0表示正常，非0表示出错；详细释义可在接口说明文档最后的错误码说明了解
     */
    code: number;
    /**
     * 会话是否成功的描述信息
     */
    message: string;
    /**
     * 会话的唯一id，用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段
     */
    sid: string;
    /**
     * 会话状态，取值为[0,1,2]；0代表首次结果；1代表中间结果；2代表最后一个结果
     */
    status: number;
  };
  payload: {
    choices: {
      /**
       * 文本响应状态，取值为[0,1,2]; 0代表首个文本结果；1代表中间文本结果；2代表最后一个文本结果
       */
      status: number;
      /**
       * 返回的数据序号，取值为[0,9999999]
       */
      seq: number;
      /**
       * 回复的对象 数组格式，但是没看见过2条，就当是数组循环吧！
       */
      text: [
        {
          /**
           * AI的回答内容
           */
          content: string;
          /**
           * 角色标识，固定为assistant，标识角色为AI
           */
          role: "assistant";
          /**
           * 结果序号，取值为[0,10]; 当前为保留字段，开发者可忽略
           */
          index: number;
        }
      ];
    };
    usage: {
      text: {
        /**
         * 保留字段，可忽略
         */
        question_tokens: number;
        /**
         * 包含历史问题的总tokens大小
         */
        prompt_tokens: number;
        /**
         * 回答的tokens大小
         */
        completion_tokens: number;
        /**
         * prompt_tokens和completion_tokens的和，也是本次交互计费的tokens大小
         */
        total_tokens: number;
      };
    };
  };
}
